/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package br.com.mocamorena.persistence.dao.impl;

import br.com.mocamorena.exception.PersistenciaException;
import br.com.mocamorena.model.Categoria;
import br.com.mocamorena.persistence.GerenciadorDeConexao;
import br.com.mocamorena.persistence.dao.CategoriaDao;
import br.com.mocamorena.view.DisplayFilter;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.List;

/**
 *
 * @author Diego
 */
public class CategoriaDaoImpl implements CategoriaDao {

    private Connection conn;
    private PreparedStatement pr;
    private ResultSet rs;

    @Override
    public boolean inserir(Categoria categoria) throws PersistenciaException {
        if (categoria == null) {
            throw new PersistenciaException("Não foi informado a categoria a cadastrar.");
        }
        boolean sucesso = false;
        try {
            conn = GerenciadorDeConexao.abreConexao();
            pr = conn.prepareStatement("INSERT INTO CATEGORIA(ID, BLOQUEADO, NOME, SHADOW) VALUES(NULL, FALSE, ?, FALSE);",
                    Statement.RETURN_GENERATED_KEYS);
            pr.setString(1, categoria.getNome());
            int linhas = pr.executeUpdate();
            if (linhas > 0) {
                sucesso = true;
                rs = pr.getGeneratedKeys();
                rs.first();
                long id = rs.getLong(1);
                categoria.setId(id);
            }
        } catch (SQLException exc) {
            StringBuilder msg = new StringBuilder("Não foi possível cadastrar a categoria.");
            msg.append("\nMotivo: ").append(exc.getMessage());
            throw new PersistenciaException(msg.toString());
        } finally {
            GerenciadorDeConexao.fechaConexao(conn, pr, rs);
        }
        return sucesso;
    }

    @Override
    public boolean atualizar(Categoria categoria) throws PersistenciaException {
        if (categoria == null) {
            throw new PersistenciaException("Não foi informado a categoria a atualizar.");
        }
        boolean sucesso = false;
        try {
            conn = GerenciadorDeConexao.abreConexao();
            pr = conn.prepareStatement("UPDATE CATEGORIA SET BLOQUEADO=?, NOME=? WHERE ID=?;");
            pr.setBoolean(1, categoria.isBloqueado());
            pr.setString(2, categoria.getNome());
            pr.setLong(3, categoria.getId());
            int linhas = pr.executeUpdate();
            if (linhas > 0) {
                sucesso = true;
            }
        } catch (SQLException exc) {
            StringBuilder msg = new StringBuilder("Não foi possível atualizar a categoria.");
            msg.append("\nMotivo: ").append(exc.getMessage());
            throw new PersistenciaException(msg.toString());
        } finally {
            GerenciadorDeConexao.fechaConexao(conn, pr);
        }
        return sucesso;
    }

    @Override
    public boolean excluir(Categoria categoria) throws PersistenciaException {
        if (categoria == null) {
            throw new PersistenciaException("Não foi informado a categoria a excluir.");
        }
        if (!isCanDeleteCategoria(categoria)) {
            throw new PersistenciaException("Não é possível excluir a categoria " + categoria.getNome().toLowerCase() + " neste momento.\n"
                    + "Antes disso, é necessário excluir todos os produtos associados a esta categoria.");
        }
        boolean sucesso = false;
        try {
            conn = GerenciadorDeConexao.abreConexao();
            pr = conn.prepareStatement("UPDATE CATEGORIA SET SHADOW=TRUE WHERE ID=?;");
            pr.setLong(1, categoria.getId());
            int linhas = pr.executeUpdate();
            if (linhas > 0) {
                sucesso = true;
            }
        } catch (SQLException exc) {
            StringBuilder msg = new StringBuilder("Não foi possível excluir a categoria.");
            msg.append("\nMotivo: ").append(exc.getMessage());
            throw new PersistenciaException(msg.toString());
        } finally {
            GerenciadorDeConexao.fechaConexao(conn, pr);
        }
        return sucesso;
    }

    @Override
    public List<Categoria> listarTodos() throws PersistenciaException {
        List<Categoria> lista = new ArrayList<Categoria>();
        try {
            conn = GerenciadorDeConexao.abreConexao();
            pr = conn.prepareStatement("SELECT ID, BLOQUEADO, NOME FROM CATEGORIA WHERE SHADOW=FALSE ORDER BY LAST_UPDATE DESC");
            rs = pr.executeQuery();
            while (rs.next()) {
                Categoria categoria = this.criarCategoria(rs);
                lista.add(categoria);
            }
        } catch (SQLException exc) {
            StringBuilder msg = new StringBuilder("Não foi possível listar as categorias.");
            msg.append("\nMotivo: ").append(exc.getMessage());
            throw new PersistenciaException(msg.toString());
        } finally {
            GerenciadorDeConexao.fechaConexao(conn, pr, rs);
        }
        return lista;
    }

    @Override
    public List<Categoria> listarDesbloqueados() throws PersistenciaException {
        List<Categoria> lista = new ArrayList<Categoria>();
        try {
            conn = GerenciadorDeConexao.abreConexao();
            pr = conn.prepareStatement("SELECT ID, BLOQUEADO, NOME FROM CATEGORIA WHERE BLOQUEADO=FALSE AND SHADOW=FALSE ORDER BY NOME");
            rs = pr.executeQuery();
            while (rs.next()) {
                Categoria categoria = this.criarCategoria(rs);
                lista.add(categoria);
            }
        } catch (SQLException exc) {
            StringBuilder msg = new StringBuilder("Não foi possível listar as categorias desbloqueados.");
            msg.append("\nMotivo: ").append(exc.getMessage());
            throw new PersistenciaException(msg.toString());
        } finally {
            GerenciadorDeConexao.fechaConexao(conn, pr, rs);
        }
        return lista;
    }

    @Override
    public List<Categoria> listarPeloNome(String nome, DisplayFilter displayFilter) throws PersistenciaException {
        List<Categoria> lista = new ArrayList<Categoria>();
        try {
            conn = GerenciadorDeConexao.abreConexao();
            if (displayFilter != DisplayFilter.TODOS) {
                pr = conn.prepareStatement("SELECT ID, BLOQUEADO, NOME FROM CATEGORIA WHERE SHADOW=FALSE AND NOME LIKE ? AND BLOQUEADO=? ORDER BY NOME");
                pr.setBoolean(2, displayFilter.getValue());
            } else {
                pr = conn.prepareStatement("SELECT ID, BLOQUEADO, NOME FROM CATEGORIA WHERE SHADOW=FALSE AND NOME LIKE ? ORDER BY NOME");
            }
            pr.setString(1, "%" + nome + "%");
            rs = pr.executeQuery();
            while (rs.next()) {
                Categoria categoria = this.criarCategoria(rs);
                lista.add(categoria);
            }
        } catch (SQLException exc) {
            StringBuilder msg = new StringBuilder("Não foi possível listar as categorias pelo nome.");
            msg.append("\nMotivo: ").append(exc.getMessage());
            throw new PersistenciaException(msg.toString());
        } finally {
            GerenciadorDeConexao.fechaConexao(conn, pr, rs);
        }
        return lista;
    }

    private Categoria criarCategoria(ResultSet rs) throws PersistenciaException {
        Categoria categoria = null;
        try {
            categoria = new Categoria(rs.getLong("ID"), rs.getBoolean("BLOQUEADO"), rs.getString("NOME"));
        } catch (SQLException sqlex) {
            StringBuilder msg = new StringBuilder("Não foi possível obter os dados da categoria.");
            msg.append("\nMotivo: ").append(sqlex.getMessage());
            throw new PersistenciaException(msg.toString());
        }
        return categoria;
    }

    private boolean isCanDeleteCategoria(Categoria categoria) throws PersistenciaException {
        boolean canDelete = true;

        try {
            conn = GerenciadorDeConexao.abreConexao();
            pr = conn.prepareStatement("SELECT COUNT(*) AS COUNT FROM PRODUTO WHERE ID_CATEGORIA=? AND SHADOW=FALSE");
            pr.setLong(1, categoria.getId());
            rs = pr.executeQuery();
            rs.first();
            int count = rs.getInt("COUNT");
            if (count > 0) {
                canDelete = false;
            }
        } catch (SQLException exc) {
            StringBuilder msg = new StringBuilder("Não foi possível contabilizar os produtos por categoria.");
            msg.append("\nMotivo: ").append(exc.getMessage());
            throw new PersistenciaException(msg.toString());
        } finally {
            GerenciadorDeConexao.fechaConexao(conn, pr, rs);
        }

        return canDelete;
    }
}
